/* $Header: cmdproc.c,v 2.3 02/07/26 12:32:52 przybyls Exp $ */


/***********************************************************************/
/*                                                                     */
/*                  Copyright Hewlett-Packard Co. 1991                 */
/*                                                                     */
/***********************************************************************/

/***********************************************************************/
/* MODULE NAME: cmdproc.c                                              */
/* ============                                                        */
/*                                                                     */
/* Author:  Bob Cook                                                   */
/*                                                                     */
/* MODULE PURPOSE: This module receives a message from the             */
/*       communications subsystem and executes the command.            */
/*                                                                     */
/*                                                                     */
/***********************************************************************/


/*
*
*  The diagram below shows the flow of information between functions
*  and queues.  The names within arrows are macros called to move
*  data to and from queues.
*
*
* ____                                                ______
*|    |<-GetPacket()---- Rd_Free_Q  <-AppendPacket()-|      |<-GetCmd()----+
*|HPIB|-AppendPacket()-> Rd_Input_Q  -GetPacket()--->|Scan()|->AppendCmd-+ |
*|----|                                              |______|            | |
*|DRTA|-AppendPacket()-> Wr_Free_Q ------->+                             | |
*|----|                                    |                             | |
*|DRTB|<-GetPacket()<-Wr_Output_Q[HPIB]<-+ |                             | |
*|----|<-GetPacket()<-Wr_Output_Q[DRTA]<-+ |  +--------- xx_Cmd_Q <------+ |
*|MIO |<-GetPacket()<-Wr_Output_Q[DRTB]<-+ |  | +------> Free_Cmd_Q -------+
*|____|<-GetPacket()<-Wr_Output_Q[MIO] <-+ |  | |
*                                        | |  | +--AppendCmd()<---+
*                                        | |  +---->GetCmd()--->+ |
*                                        | |                    | |
*                                        | |                  ___________
*                                        | |                 |           |
*                                        | +-> GetRespBuf()->| xx_Cmds() |
*                                        +<-- SendRespBuf()<-|           |
*                                                            |___________|
*
*                                                          SetUpRespHdr()
*/


/*****************************/
/*   GLOBAL INCLUDE FILES    */
/*****************************/
#include  <typedefs.h>
#include  <error.h>
#include  <stddef.h>
#include  <std_ops.h>
#include  <i_op.h>
#include  <config.h>
#include  <mio.h>
#include  <cmd_set.h>
#include  <cmdproc.h>
#include  <method.h>
#include  <hostutil.h>
#include  <wkfutil.h>
#include  <iomap.h>
#include  <set.h>
#include  <duart.h>


/*****************************/
/*   LOCAL INCLUDE FILES     */
/*****************************/

/*****************************/
/*   LOCAL DEFINES           */
/*****************************/

/* if BC_DEBUG is defined debug buffers are created and statics become global */
/*
#define BC_DEBUG
*/

/* when debugging make variables global for emulator testing */
#ifdef BC_DEBUG
#   define SCOPE
#else
#   define  SCOPE  static
#endif


/*****************************/
/*   GLOBAL VARIABLES        */
/*****************************/


IN_MSG_CB_TYPE  Cmd_Proc_CB; /* variables used in CmdProc for Scan */
IN_MSG_CB_TYPE  Wkfile_CB;   /* variables used in Wkfile for Scan */
MIO_HDR_TYPE  *pIn_Packet;   /* pointer to current read packet header */
BIT8           DC_Use_Check_Area;   /* tells workfile functions to use */
                                    /*   check area or active workfile */
INSTALL_STATE_TYPE Install_State;

/*** create buffers for non MIO ports which look like MIO buffers ******/

/******** create MIO Read Packets *********/
/*  an MIO Packet consists of a header and its associated buffer */
/* create MIO Read packet headers */
MIO_HDR_TYPE   Rd_Hdr[NUM_RD_PACKETS];
/* create a queue of free read packets */
QUEUE_TYPE      Rd_Free_Q;
pthread_mutex_t Rd_Free_Q_Mut  = PTHREAD_MUTEX_INITIALIZER;
/* create a queue of full read packets for peripheral (cmd processor) */
QUEUE_TYPE      Rd_Input_Q;
pthread_mutex_t Rd_Input_Q_Mut  = PTHREAD_MUTEX_INITIALIZER;

#ifndef mccabe
#  pragma SECTION UDATA=DRam
#endif
/* create MIO Read Packet data buffers */
U_INT8   Rd_Buf[NUM_RD_PACKETS][RD_BUF_SIZE];
#ifndef mccabe
#  pragma SECTION UNDO
#endif

/******** create MIO Write Buffers *********/

/*  an MIO Packet consists of a header and its associated buffer */
/* create MIO Write packet headers */
MIO_HDR_TYPE   Wr_Hdr[NUM_WR_PACKETS];
/* create a queue of free write packets */
QUEUE_TYPE      Wr_Free_Q;
pthread_mutex_t Wr_Free_Q_Mut  = PTHREAD_MUTEX_INITIALIZER;
/* create a queue of full write packets from peripheral (cmd processor) */
QUEUE_TYPE      Wr_Output_Q[NUM_PORTS];
pthread_mutex_t Wr_Output_Q_Mut  = PTHREAD_MUTEX_INITIALIZER;

#ifndef mccabe
#  pragma SECTION UDATA=DRam
#endif
/* create MIO Write Packet data buffers */
U_INT8   Wr_Buf[NUM_WR_PACKETS][WR_BUF_SIZE];
#ifndef mccabe
#  pragma SECTION UNDO
#endif


/******** create Cmd_In Buffers *********/
/* create command buffers */
CMD_TYPE   Cmd_In[NUM_CMD_BUFS];
/* create a queue of free command buffers */
CMD_QUEUE_TYPE      Free_Cmd_Q;
/* create a queue of GC commands (general instrument) */
CMD_QUEUE_TYPE      GC_Cmd_Q;
/* create a queue of S1 commands (signal 1) */
CMD_QUEUE_TYPE      S1_Cmd_Q;
/* create a queue of S2 commands (signal 2) */
CMD_QUEUE_TYPE      S2_Cmd_Q;
/* create a queue of SP commands (signal plot) */
CMD_QUEUE_TYPE      SP_Cmd_Q;
/* create a queue of SS commands (synchronized signals ) */
CMD_QUEUE_TYPE      SS_Cmd_Q;
/* create a queue of CC commands (chemcomm) */
CMD_QUEUE_TYPE      CC_Cmd_Q;
/* create a queue of DT commands (diagnostic) */
CMD_QUEUE_TYPE      DT_Cmd_Q;
/* create a queue of OV commands (oven) */
CMD_QUEUE_TYPE      OV_Cmd_Q;
/* create a queue of IX commands (inlet) */
CMD_QUEUE_TYPE      IX_Cmd_Q;
/* create a queue of DX commands (detector) */
CMD_QUEUE_TYPE      DX_Cmd_Q;
/* create a queue of CX commands (column) */
CMD_QUEUE_TYPE      CX_Cmd_Q;
/* create a queue of AX commands (aux) */
CMD_QUEUE_TYPE      AX_Cmd_Q;
/* create a queue of VX commands (valves) */
CMD_QUEUE_TYPE      VX_Cmd_Q;
/* create a queue of IQ commands (instrument commands oven inlet
                                     detector column aux and valves) */
CMD_QUEUE_TYPE      IQ_Cmd_Q;
/* create a queue for automatic sampler */
CMD_QUEUE_TYPE      AS_Cmd_Q;
/* create a queue for EOS automatic sampler */
CMD_QUEUE_TYPE      _0X_Cmd_Q;
/* create a queue of PX commands (pass through commands for sampler port */
/* message will not go through Scan, Cmd struct's "parms" contains entire msg */
CMD_QUEUE_TYPE      PX_Cmd_Q;
/* create a queue for temperary development commands */
CMD_QUEUE_TYPE      TP_Cmd_Q;
/* create a queue of Q0 commands (internal IQ location - use GetMsg) */
/* message will not go through Scan, Cmd struct's "parms" contains entire msg */
CMD_QUEUE_TYPE      Q0_Cmd_Q;
/* create a queue of Q1 commands (internal IQ location - use GetCmd) */
/* message will go through Scan, so parameters are parsed out in Cmd struct */
CMD_QUEUE_TYPE      Q1_Cmd_Q;
/* create a queue of Q2 commands (use GetQ2Msg) */
/* message will not go through Scan, Cmd struct's "parms" contains entire msg */
CMD_QUEUE_TYPE      Q2_Cmd_Q;
/* create a queue of Als ping commands (internal IQ location - use GetCmd) */
/* message will go through Scan, so parameters are parsed out in Cmd struct */
CMD_QUEUE_TYPE      Ping_Q;
/* create a queue of Q3 commands (internal IQ location - use GetMsg) */
/* message will not go through Scan, Cmd struct's "parms" contains entire msg */
CMD_QUEUE_TYPE      Q3_Cmd_Q;
/* create a queue of Als injector commands (internal IQ location - use GetCmd) */
/* message will go through Scan, so parameters are parsed out in Cmd struct */
CMD_QUEUE_TYPE      Inj_Q;
/* create a queue of headspace sampler commands (internal IQ location - use GetCmd */
/* no commas are used so parameters are all returned in parms[1] */
CMD_QUEUE_TYPE      HS_Cmd_Q;


pthread_mutex_t Cmd_Q_Mut  = PTHREAD_MUTEX_INITIALIZER;

#ifndef mccabe
#  pragma SECTION UDATA=DRam
#endif
/* reserve space for upload and download buffers */
DWNLD_WKFILE_TYPE   Dwnld_wkfile[];
#ifndef mccabe
#  pragma SECTION UNDO
#endif

/*** create table for pass thru communication paths ******/
PATH_TYPE Com_Path[NUM_PATHS];


/*****************************/
/*   EXTERNAL VARIABLES      */
/*****************************/


extern  QUEUE_TYPE  MIO_Rd_Free_Q;

/* Control Block for each UART */
extern DUART_CB_TYPE  Duart_CB[5];

#ifdef BC_DEBUG

typedef struct
{

   U_INT8              status;
   U_INT8              error;
   MIO_BYTE_HDR_TYPE  *pack_hdr;
   U_INT8              buf_type;
   U_INT8              cmd;
   U_INT8              cmd_mod;
   U_INT8              ret_stat;
   MIO_BYTE_HDR_TYPE  *append_hdr;
   U_INT8              IOstatus;
   U_INT8              IOerror;
   MIO_BYTE_HDR_TYPE  *IOpack_hdr;

} MIO_TEST_INFO_TYPE;

#define MAX_MIO_TEST_INFO_COUNT 256

extern MIO_TEST_INFO_TYPE   Mio_Test_Info[];
extern U_INT8               Mio_Test_Info_Count;

#endif


/*****************************/
/*   STATIC VARIABLES        */
/*****************************/


#ifdef  BC_DEBUG
#  ifndef mccabe
#    pragma SECTION UDATA=DRam
#  endif
   /*  debug buffers */
   U_INT8  TMP_CP[2048];
   U_INT8  *pTMP_CP;
   U_INT8  *pTMP_CP_End;
#  ifndef mccabe
#    pragma SECTION UNDO
#  endif
#endif



/*****************************/
/*   MACROS                  */
/*****************************/
/*==========================================================================*
 * MACRO: SetUpErrorMsgInCmd                                                *
 *                                                                          *
 * PURPOSE: Moves first six chars of message into pCmd header, if possible, *
 *          which allows CmdErrorHandler to use them.                       *
 *          The six charactors are: "No_Cmd".                               *
 * WARNING:                                                                 *
 *==========================================================================*/
/* void SetUpErrorMsgInCmd(IN_MSG_CB_TYPE *msg,CMD_TYPE p_cmd) */
#define SetUpErrorMsgInCmd(msg,p_cmd)                                      \
{                                                                          \
   /* if 6 printable chars, blindly copy first 6 chars for error info */   \
   if( ((*msg).in_msg_len > 5) &&                                          \
         (ISPRINTABLE(*(*msg).pin_msg)) &&                                 \
         (ISPRINTABLE(*((*msg).pin_msg+1))) &&                             \
         (ISPRINTABLE(*((*msg).pin_msg+2))) &&                             \
         (ISPRINTABLE(*((*msg).pin_msg+3))) &&                             \
         (ISPRINTABLE(*((*msg).pin_msg+4))) &&                             \
         (ISPRINTABLE(*((*msg).pin_msg+5))) )                              \
   {                                                                       \
      Copy2((*msg).pin_msg,p_cmd->dsap.char_dsap);                         \
      Copy2((*msg).pin_msg+2,p_cmd->ssap.char_ssap);                       \
      Copy2((*msg).pin_msg+4,p_cmd->opcode.char_op);                       \
   }                                                                       \
   else                                                                    \
   {                                                                       \
      /* not enough valid chars received */                                \
      Copy2((BIT8 *)"No",p_cmd->dsap.char_dsap);                           \
      Copy2((BIT8 *)"_C",p_cmd->ssap.char_ssap);                           \
      Copy2((BIT8 *)"md",p_cmd->opcode.char_op);                           \
   }                                                                       \
}

/*****************************/
/*   IMPLEMENT SECTION       */
/*****************************/


/***********************************************************************/
/* FUNCTION: Scan                                                      */
/* ========                                                            */
/*                                                                     */
/* PURPOSE:                                                            */
/*                                                                     */
/*   An instruction consists of an DSAP, SSAP, OPCODE and PARAMETERS.  */
/*   It must contain DSAP, SSAP and OPCODE. Legal characters for       */
/*   DSAP, SSAP and OPCODE are of digits (0-9) or alpha                */
/*   characters (a-z and A-Z).  Parameters must start with             */
/*   digit, alpha, '.', '-', '+'or '?' and all following characters    */
/*   must consist of digit, '.', or alpha.  All spaces are removed     */
/*   before after and within parameters.                               */
/*                                                                     */
/*   The function Scan will scan through the input message and find    */
/*   the DSAP, SSAP, OPCODE and PARAMETERS of one instruction and      */
/*   place them in a structure pointed to by p_cmd.                    */
/*                                                                     */
/*                                                                     */
/*                                                                     */
/* RETURNED VALUE: none                                                */
/*                                                                     */
/* FILE SCOPE STATICS USED:                                            */
/*                                                                     */
/*                                                                     */
/* CALLS:                                                              */
/*                                                                     */
/* LIMITATIONS:                                                        */
/*     Assumes that the DSAP, SSAP, and OPCODE are 2 byes when         */
/*     copying from input instruction to cmd structure.                */
/*     (Copy2 is used.)                                                */
/*                                                                     */
/*                                                                     */
/* WARNINGS:                                                           */
/*                                                                     */
/*                                                                     */
/***********************************************************************/

#ifndef mccabe
#  pragma SECTION PROG=rom3
#endif

UI_ERR Scan(IN_MSG_CB_TYPE *msg,CMD_TYPE  *p_cmd)

{
   INT16 i;
   INT16 parms_index, scan_state;
   UI_ERR  error_code;
   BIT8  not_0x;


   error_code = OK;
   not_0x     = TRUE;

   /* remove any non-printable chars at the beginning of the msg */
   while( (*msg).in_msg_len > 0 && !ISPRINTABLE(*(*msg).pin_msg) )
   {
      (*msg).in_msg_len--;
      (*msg).pin_msg++;
   }

   /* remove nonprintable chars at end of msg */
   while( (*msg).in_msg_len > 0 && !ISPRINTABLE(*((*msg).pin_msg + (*msg).in_msg_len - 1)) )
   {
      (*msg).in_msg_len--;
   }

   /************* get DSAP ****************/

   if((*msg).in_msg_len < DSAP_LEN)
      return  NO_INSTR;  /* no instruction */

   if( ISALPHA(*(*msg).pin_msg) || ISDIGIT(*(*msg).pin_msg) || ISALS(*(*msg).pin_msg) )     /* first charact accepted */
   {
      Copy2((*msg).pin_msg,p_cmd->dsap.char_dsap);    /* read instruction */
      (*msg).pin_msg += DSAP_LEN;
      (*msg).in_msg_len -= DSAP_LEN;
      while((*msg).in_msg_len > 0 && STRIP(*(*msg).pin_msg))       /* filter out HT,SP) */
      {
         (*msg).in_msg_len--;
         (*msg).pin_msg++;
      }

      if (p_cmd->dsap.char_dsap[0] == '0')
      {
         not_0x = FALSE;
         if ((p_cmd->comm_port == INJECTOR1_PORT) ||
             (p_cmd->comm_port == INJECTOR2_PORT) ||
             (p_cmd->comm_port == TRAY_PORT)         )
         {
            return NO_INSTR;   /* Throw away sampler tower spontaneous log messages */
         }
      }
   }
   else
   {
      return  NO_INSTR;  /* bad instruction syntax */
   }


   /************* get SSAP ****************/

   if((*msg).in_msg_len < SSAP_LEN)
      return  NO_INSTR;  /* no instruction */

   if( ISALPHA(*(*msg).pin_msg) || ISDIGIT(*(*msg).pin_msg) || ISALS(*(*msg).pin_msg) )   /* first charact accepted */
   {
      Copy2((*msg).pin_msg,p_cmd->ssap.char_ssap);       /* read instruction */
      (*msg).pin_msg += SSAP_LEN;
      (*msg).in_msg_len -= SSAP_LEN;
   }
   else
   {
      return  NO_INSTR;  /* bad instruction syntax */
   }

   /*
    * Is this command going to by pass the parser and go to an IQ process?
    *  If so, copy entire meassage including DSAP and SSAP to parms.
    *              Q0 ALS Pass Through
    *              Q3  ALS Pass Through, second channel
    *              Q2 diagnostics
    *              Px pass through  response
    *       EOS:   0x is NOT pass through commands from host except for CP commands
    *                and that case handled after opcode is captured.
    */

   if( (p_cmd->dsap.int_dsap == MAKEINT('Q','0')) ||
       (p_cmd->dsap.int_dsap == MAKEINT('Q','2')) ||
       (p_cmd->dsap.int_dsap == MAKEINT('Q','3')) ||
       (p_cmd->dsap.char_dsap[0] == 'P')             )
   {
      parms_index = 0;                  /* initialize parameter index */
      *p_cmd->parmv = 0;                /* set number of parameters to zero */

      if( (*msg).in_msg_len > 0)
      {
         /* indicate one parameter */
         p_cmd->parmv[0] = 1;

         Copy2(p_cmd->dsap.char_dsap,&p_cmd->parms[parms_index]);
         parms_index += 2;
         Copy2(p_cmd->ssap.char_ssap,&p_cmd->parms[parms_index]);
         parms_index += 2;

         /* copy next two byes for error msg if needed */
         if( (*msg).in_msg_len > 1)
         {
            p_cmd->opcode.char_op[0]= *(*msg).pin_msg;
            p_cmd->opcode.char_op[1]= *((*msg).pin_msg+1);
         }

         /* copy all bytes until end or max length is found */
         while( ((*msg).in_msg_len > 0) && (parms_index < MAX_PARM_LEN-1) )
         {
            p_cmd->parms[parms_index++] = *(*msg).pin_msg;
            (*msg).in_msg_len--;
            (*msg).pin_msg++;
         }
      }
      /* terminate with null */
      p_cmd->parms[parms_index]=0;
      return  error_code;
   }

   /************* get OPCODE ****************/

   /* remove spaces between SSAP and OPCODE */
   while((*msg).in_msg_len > 0 && STRIP(*(*msg).pin_msg))       /* filter out HT,SP) */
   {
      (*msg).in_msg_len--;
      (*msg).pin_msg++;
   }

   if((*msg).in_msg_len < MIN_OPCODE_LEN)
      return  NO_INSTR;  /* no instruction */

   i = 0;
   /* copy chars until get to space or ; */
   while( (ISPRINTABLE(*(*msg).pin_msg)) && !(*(*msg).pin_msg == ';')  &&
               (i <= MAX_OPCODE_LEN) && ((*msg).in_msg_len > 0) )
   {
      p_cmd->opcode.char_op[i] = *(*msg).pin_msg;
      (*msg).in_msg_len--;
      (*msg).pin_msg++;
      i++;
   }

   /* terminate string */
   p_cmd->opcode.char_op[i] = 0;

   if( i == (MAX_OPCODE_LEN + 1) )
   {
      return  INVALID_OP;  /* bad instruction syntax */
   }

   while( ((*msg).in_msg_len > 0) && STRIP(*(*msg).pin_msg) )    /* filter out HT,SP) */
   {
      (*msg).in_msg_len--;
      (*msg).pin_msg++;
   }


   /************* get PARAMETERS ****************/

   /******* handle display command parameters *******/
   /*     The display command is special because it has
    *     only one parameter and that parameter may include
    *     ',' character.
    *     Also pass 0xVSIF, 0xVSIB, 0xTOWER, 0xTRAY_POS, 0xMIX,
    *     and 0xMOVE the same way for Mike's
    *     wierd sampler commands that use spaces as param delimiters.
    */

   if (( p_cmd->dsap.int_dsap == MAKEINT('G','C') &&
         p_cmd->opcode.char_op[0] == 'D'             )        ||
       ( !not_0x &&
         ( ((p_cmd->opcode.int_op == MAKEINT('V','S')) &&
            (p_cmd->opcode.char_op[2] == 'I')             )||
           ((p_cmd->opcode.int_op == MAKEINT('T','O')) &&
            (p_cmd->opcode.char_op[2] == 'W')             )||
           (p_cmd->opcode.int_op == MAKEINT('R','E'))      ||
           (p_cmd->opcode.int_op == MAKEINT('T','R'))      ||
           (p_cmd->opcode.int_op == MAKEINT('M','I'))      ||
           (p_cmd->opcode.int_op == MAKEINT('M','O'))         )  ) )
   {
      parms_index = 0;                  /* initialize parameter index */
      *p_cmd->parmv = 0;                /* set number of parameters to zero */

      while((*msg).in_msg_len > 0 && STRIP(*(*msg).pin_msg))       /* filter out HT,SP) */
      {
         (*msg).in_msg_len--;
         (*msg).pin_msg++;
      }

      if( (*msg).in_msg_len > 0)
      {
         p_cmd->parmv[0] = 1;
         /* copy all bytes until end or ; or max length is found */
         while( ((*msg).in_msg_len > 0) && (*(*msg).pin_msg != ';') &&
                                       (parms_index < MAX_PARM_LEN-1) )
         {
            p_cmd->parms[parms_index++] = *(*msg).pin_msg;
            (*msg).in_msg_len--;
            (*msg).pin_msg++;
         }
      }
      p_cmd->parms[parms_index]=0;
      return  error_code;
   }

   /******* handle Program Flash   parameters *******/
   /*     The DTPF command is special because it has
    *     only one parameter and that parameter may include
    *     ',' and ';' characters.
    */

   if ( p_cmd->dsap.int_dsap == MAKEINT('D','T') &&
        p_cmd->opcode.int_op == MAKEINT('P','F') )
   {
      parms_index = 0;                  /* initialize parameter index */
      *p_cmd->parmv = 0;                /* set number of parameters to zero */

      while((*msg).in_msg_len > 0 && STRIP(*(*msg).pin_msg))       /* filter out HT,SP) */
      {
         (*msg).in_msg_len--;
         (*msg).pin_msg++;
      }

      if( (*msg).in_msg_len > 0)
      {
         p_cmd->parmv[0] = 1;
         /* copy all bytes until end  or max length is found */
         while( ((*msg).in_msg_len > 0) &&
                                       (parms_index < MAX_PARM_LEN-1) )
         {
            p_cmd->parms[parms_index++] = *(*msg).pin_msg;
            (*msg).in_msg_len--;
            (*msg).pin_msg++;
         }
      }
      p_cmd->parms[parms_index]=0;
      return  error_code;
   }

   /******* handle Printer Pass-Thru   parameters *******/
   /*     The CCPR command is special because it has
    *     only one parameter and that parameter may include
    *     ',' and ';' characters.
    */

   if ( p_cmd->dsap.int_dsap == MAKEINT('C','C') &&
        ( p_cmd->opcode.int_op == MAKEINT('P','0') ) ||
        ( p_cmd->opcode.int_op == MAKEINT('P','1') ) ||
        ( p_cmd->opcode.int_op == MAKEINT('P','2') ) )
   {
      parms_index = 0;                  /* initialize parameter index */
      *p_cmd->parmv = 0;                /* set number of parameters to zero */

      while((*msg).in_msg_len > 0 && STRIP(*(*msg).pin_msg))       /* filter out HT,SP) */
      {
         (*msg).in_msg_len--;
         (*msg).pin_msg++;
      }

      if( ( (*msg).in_msg_len-- > 0) && ( *(*msg).pin_msg++ == ';') )
      {
         p_cmd->parmv[0] = 1;
         /* copy all bytes until end  or max length is found */
         while( ((*msg).in_msg_len > 0) &&
                                       (parms_index < MAX_PARM_LEN-1) )
         {
            p_cmd->parms[parms_index++] = *(*msg).pin_msg;
            (*msg).in_msg_len--;
            (*msg).pin_msg++;
         }
      }
      p_cmd->parms[parms_index]=0;

      /* route the response to the selected port */
      switch (p_cmd->opcode.int_op)
      {
         case MAKEINT('P','0'):
            p_cmd->comm_port = DRTA_PORT;
            break;
         case MAKEINT('P','1'):
            p_cmd->comm_port = DRTB_PORT;
            break;
         default:
            break;
      }
      return  error_code;
   }

   /******* handle Sampler CP command Parameters *******/
   /*     The 0xCP commands are special.  Everything after
    *     the opcode is treated as one parameter (leading spaces discarded).
    */
   if ((p_cmd->dsap.char_dsap[0] == '0') &&
       (p_cmd->opcode.int_op == MAKEINT('C','P')) )
   {
      parms_index = 0;                  /* initialize parameter index */
      *p_cmd->parmv = 0;                /* set number of parameters to zero */

      /* remove spaces between OPCODE and pass-through DSAP/SSAP */
      while((*msg).in_msg_len > 0 && STRIP(*(*msg).pin_msg))       /* filter out HT,SP) */
      {
         (*msg).in_msg_len--;
         (*msg).pin_msg++;
      }

      if( (*msg).in_msg_len > 0)
      {
         /* indicate one parameter */
         p_cmd->parmv[0] = 1;

         /* copy all bytes until end or max length is found */
         while( ((*msg).in_msg_len > 0) && (parms_index < MAX_PARM_LEN-1) )
         {
            p_cmd->parms[parms_index++] = *(*msg).pin_msg;
            (*msg).in_msg_len--;
            (*msg).pin_msg++;
         }

      }
      else
      {
         error_code = SYNTAX_ERROR;  /* nothing to pass through */
      }

      /* terminate with null */
      p_cmd->parms[parms_index]=0;
      return  error_code;
   }


   /************ handle normal parameters ************/

   /*
    *   PARSE PARAMETERS:
    *                         &
    *                       +----+
    *                       |    |
    *                       |    v
    *                      PARAMETER
    *                    ^  |    ^  \
    *                   /   |    |   \
    *                # /    |@   |$   \ *
    *                 /     |    |     \
    *                /  !   v    |   @  v           ----+
    *     ---->  BEGIN --->SEPARATE<--- WHITE_SPACE     |*
    *             |\       || |   ^      ^   ^      <---+
    *             | \      || |   |     /    |
    *             |  \     || +---+    /     |
    *             | " \   {|| @ or *  / ?    |
    *             |    \   ||        /       |
    *             |     \  ||"      /        |
    *             |      v |v      /         |
    *           { |        | STRING        } |
    *             |        | |    ^          |
    *             |        | |    |          |
    *             |        | +----+          |
    *             |        |   +             |
    *             |        v                 |
    *             +------> STRING2  ---------+
    *                      |    ^
    *                      |    |
    *                      +----+
    *                        -
    *
    *     # - rec param char: save char, save loc of char
    *     ! - rec sep char: save 0, inc param count, save 0,
    *                          save loc of 0, dec index
    *     @ - rec sep char: inc index,save 0, inc param count,
    *                          save 0, save loc of 0, dec index
    *     & - rec param char: inc index, save char
    *     $ - rec param char: inc index, save char, save loc of char
    *     % - rec sep char: inc index, save 0 save index, inc count
    *     * - rec white space: do nothing
    *     " - rec double quote char: save loc of char
    *     + - rec any char except " or ;: inc index, save char
    *     ? - rec double quote char: do nothing
    *     { - rec left curly bracket char: save loc of char
    *     - - rec any char except ^ or ;: inc index, save char
    *     } - rec right curly bracket char: do nothing
    *
    */

   parms_index = 0;                  /* initialize parameter index */
   *p_cmd->parmv = 0;                /* set number of parameters to zero */
   scan_state = BEGIN;               /* set initial state to find first parm */

   while(!( ((*(*msg).pin_msg ==';') && not_0x) || error_code || (*msg).in_msg_len == 0 ))
   {
      if( (*(*msg).pin_msg == ';') && !not_0x)  /* only 0x ";"'s should reach here */
      {
         if (scan_state != BEGIN)
         {
            parms_index++;
         }
         else
         {
            p_cmd->parmv[p_cmd->parmv[0]] = parms_index; /*set location*/
         }
         scan_state = SEPARATE;
         p_cmd->parms[parms_index] = 0; /* end of current parameter */
         p_cmd->parmv[0]++; /* there is another parameter coming */

         /* output semicolon as an individual parameter              */
         parms_index++;
         p_cmd->parmv[p_cmd->parmv[0]] = parms_index; /*set location */
         p_cmd->parms[parms_index] = ';';
         parms_index++;
         p_cmd->parms[parms_index] = 0;
         p_cmd->parmv[0]++; /* there is another parameter coming */

         /* save null string in case empty param (may be overwritten)*/
         parms_index++;
         p_cmd->parms[parms_index] = 0;
         p_cmd->parmv[p_cmd->parmv[0]] = parms_index; /*set location */
         parms_index--;
      }
      else
      {
         /* pass through switch statement once for each input character */
         switch(scan_state)
         {

         case BEGIN :
            /*
             * if first character of parameter is a double quote go to
             *   STRING state, else if it a printable character then
             *   copy char to cmd_in and continue reading characters in PARAMETER
             *   STATE. If character is the separator character save null string,
             *   otherwise, issue syntax error.
             */

            p_cmd->parmv[0] = 1;
            if( *(*msg).pin_msg == '"' )
            {
               scan_state = STRING;
               p_cmd->parmv[p_cmd->parmv[0]] = 0;
               /* don't store '"' so move index back to prepare for string */
               parms_index--;
            }
            else
            {
               if( *(*msg).pin_msg == '{' )
               {
                  scan_state = STRING2;
                  p_cmd->parmv[p_cmd->parmv[0]] = 0;
                  /* don't store '{' so move index back to prepare for string */
                  parms_index--;
               }
               else
               {
                  if( ISPRINTABLE(*(*msg).pin_msg) && !(SEPARATOR(*(*msg).pin_msg)) )
                  {
                     scan_state = PARAMETER;
                     p_cmd->parms[parms_index] = *(*msg).pin_msg;
                     p_cmd->parmv[p_cmd->parmv[0]] = 0;
                  }
                  else
                  {
                     if(SEPARATOR(*(*msg).pin_msg))          /* more parameters */
                     {
                        scan_state = SEPARATE;
                        p_cmd->parms[parms_index] = 0; /* end of current parameter */
                        p_cmd->parmv[p_cmd->parmv[0]] = parms_index; /*set location*/
                        p_cmd->parmv[0]++; /* there is another parameter coming */

                        /* save null string in case empty param (may be overwritten)*/
                        parms_index++;
                        p_cmd->parms[parms_index] = 0;
                        p_cmd->parmv[p_cmd->parmv[0]] = parms_index; /*set location */
                        parms_index--;
                     }
                     else
                     {
                        error_code = INSTR_SYNTAX;
                     }
                  }
               }
            }
            break;

         case PARAMETER    :
            /*
             * Verify that size and number of parameters are reasonable.
             *   Also copy charactor parameter to p_cmd.
             *   A valid character is and printable character. Spaces
             *   between parameters and separator are removed.  If
             *   separator is found, setup for next character.
             */

            if( parms_index >= (MAX_PARM_LEN - 2) )
            {
               error_code = PARAM_LENGTH;
               break;
            }
            if( ISPRINTABLE(*(*msg).pin_msg) && !(SEPARATOR(*(*msg).pin_msg)) )
            {
               parms_index++;
               p_cmd->parms[parms_index] = *(*msg).pin_msg;
               break;
            }

            if ((SEPARATOR(*(*msg).pin_msg))  ||      /* more parameters */
                (!not_0x && (*(*msg).pin_msg ==' ') && (p_cmd->opcode.int_op == MAKEINT('D','A')) ) )
            /* Note: the !not_0x case is for the als DAte command that has */
            /* an optional "?" following the time&date value.  There may   */
            /* or may not be a space between the # and the ?.  This code   */
            /* turns a possible space into a separator, the no-space form  */
            /* is handled in the command.                                  */
            {
               scan_state = SEPARATE;
               parms_index++;
               p_cmd->parms[parms_index] = 0; /* end of current parameter */
               p_cmd->parmv[0]++; /* separator - another is parameter coming */

               /* save null string in case empty param (may be overwritten) */
               parms_index++;
               p_cmd->parms[parms_index] = 0;
               p_cmd->parmv[p_cmd->parmv[0]] = parms_index; /* set location */
               parms_index--;

               break;
            }
            if(STRIP(*(*msg).pin_msg))
            {
               scan_state = WHITE_SPACE;
            }
            else
            {
               error_code = INSTR_SYNTAX;
            }
            break;

         case STRING    :
            /*
             *   Also copy charactor to p_cmd.
             *   All characters are copied until a double quote is found.
             *   if a double quote is found nothing happens, but the
             *   state is changed to WHITE_SPACE.
             */

            if( parms_index >= (MAX_PARM_LEN - 1) )
            {
               error_code = PARAM_LENGTH;
               break;
            }
            if( *(*msg).pin_msg != '"' )
            {
               /* copy char to p_cmd */
               parms_index++;
               p_cmd->parms[parms_index] = *(*msg).pin_msg;
               break;
            }
            else
            {
               /*  *(*msg).pin_msg == '"'  */
               scan_state = WHITE_SPACE;
            }
            break;

         case STRING2   :
            /*
             *   Also copy charactor to p_cmd.
             *   All characters are copied until a } is found.
             *   if a } is found nothing happens, but the
             *   state is changed to WHITE_SPACE.
             */

            if( parms_index >= (MAX_PARM_LEN - 1) )
            {
               error_code = PARAM_LENGTH;
               break;
            }
            if( *(*msg).pin_msg != '}' )
            {
               /* copy char to p_cmd */
               parms_index++;
               p_cmd->parms[parms_index] = *(*msg).pin_msg;
               break;
            }
            else
            {
               /*  *(*msg).pin_msg == '}'  */
               scan_state = WHITE_SPACE;
            }
            break;



         case WHITE_SPACE:
            /* remove any white space before separator */
            if(STRIP(*(*msg).pin_msg))
               break;
            if(SEPARATOR(*(*msg).pin_msg))
            {
               scan_state = SEPARATE;
               parms_index++;
               p_cmd->parms[parms_index] = 0; /* end of current parameter */
               p_cmd->parmv[0]++; /* there is another parameter coming */

               /* save null string in case empty param (may be overwritten) */
               parms_index++;
               p_cmd->parms[parms_index] = 0;
               p_cmd->parmv[p_cmd->parmv[0]] = parms_index; /* set location */
               parms_index--;
            }
            else
            {
               error_code = INSTR_SYNTAX;
            }
            break;

         case SEPARATE :
            /*
             *  Look for first char by stripping white space. When first
             *     character is found, copy it and go to PARAMETER STATE.
             */

            if(STRIP(*(*msg).pin_msg))
            {
               break;
            }
            /* check if more parameters are allowed */
            if( *p_cmd->parmv > MAX_PARM_NUM )
            {
               error_code = NUM_OF_PARAM;
               break;
            }
            /* check if parameter length exceeds max */
            if( parms_index >= (MAX_PARM_LEN - 2) )
            {
               error_code = PARAM_LENGTH;
               break;
            }
            if( *(*msg).pin_msg == '"' )
            {
               scan_state = STRING;
               parms_index++;
               p_cmd->parmv[p_cmd->parmv[0]] = parms_index;
               /* don't store '"' so move index back to prepare for string */
               parms_index--;
            }
            else if( *(*msg).pin_msg == '{' )
            {
               scan_state = STRING2;
               parms_index++;
               p_cmd->parmv[p_cmd->parmv[0]] = parms_index;
               /* don't store '{' so move index back to prepare for string */
               parms_index--;
            }
            else
            {
               if( ISPRINTABLE(*(*msg).pin_msg) && !(SEPARATOR(*(*msg).pin_msg)) )
               {
                  scan_state = PARAMETER;
                  parms_index++;
                  p_cmd->parmv[p_cmd->parmv[0]] = parms_index;
                  p_cmd->parms[parms_index] = *(*msg).pin_msg;
               }
               else
               {
                  if(SEPARATOR(*(*msg).pin_msg))
                  {
                     scan_state = SEPARATE;
                     parms_index++;
                     p_cmd->parms[parms_index] = 0; /* end of current parameter */
                     p_cmd->parmv[p_cmd->parmv[0]] = parms_index; /* set location*/
                     p_cmd->parmv[0]++; /* there is another parameter coming */

                     /* save null string in case empty param (may be overwritten)*/
                     parms_index++;
                     p_cmd->parms[parms_index] = 0;
                     p_cmd->parmv[p_cmd->parmv[0]] = parms_index; /* set location*/
                     parms_index--;
                  }
                  else
                  {
                     error_code = INSTR_SYNTAX;
                  }
               }
            }
            break;
         }  /* switch */
      }

      (*msg).in_msg_len--;
      (*msg).pin_msg++;

   }   /* while */

   /* add string terminator to end of last parameter */
   parms_index++;
   p_cmd->parms[parms_index]=0;

   /* filter out follow spaces and tabs */
   while((*msg).in_msg_len > 0 && STRIP(*(*msg).pin_msg))       /* filter out HT,SP) */
   {
      (*msg).in_msg_len--;
      (*msg).pin_msg++;
   }

   return  error_code;
}

/***********************************************************************/
/* END FUNCTION: Scan                                                  */
/***********************************************************************/

#ifndef mccabe
#  pragma SECTION UNDO
#endif



/***********************************************************************/
/* FUNCTION: InitializeCmdProc                                         */
/* ========                                                            */
/*                                                                     */
/* PURPOSE: Initialize the buffers used by the command processor       */
/*                                                                     */
/*                                                                     */
/*                                                                     */
/* RETURNED VALUE: none                                                */
/*                                                                     */
/*                                                                     */
/* CALLS: none                                                         */
/*                                                                     */
/* LIMITATIONS:  none                                                  */
/*                                                                     */
/***********************************************************************/

#ifndef mccabe
#  pragma SECTION PROG=boot
#endif

void InitializeCmdProc(void)
{
   U_INT16 i;      /* indexing variable */

   /* initialize workfile pointer to active workfile */
    USE_ACTIVE_WKFILE();

   /* initialize error count */
    for (i=0; i<=4; i++)
    {
       Host_Error_Count[i] = 0;
    }


    /******  READ PACKETS  ******/


    pthread_mutex_lock(&Rd_Input_Q_Mut);
    Rd_Input_Q.head = NULL;
    Rd_Input_Q.tail = NULL;
    Rd_Input_Q.num_entries = 0;
    pthread_mutex_unlock(&Rd_Input_Q_Mut);


    pthread_mutex_lock(&Rd_Free_Q_Mut);
    /* initialize read queues */
    Rd_Free_Q.head = NULL;
    Rd_Free_Q.tail = NULL;
    Rd_Free_Q.num_entries = 0;
    /* initialize read packet headers */
    for (i = 0; i < NUM_RD_PACKETS ; i++)
    {
      Rd_Hdr[i].buf_type = DATA_RD;
      /* find 16 bit offset (required for MIO header) */
/*------------changed by wangwei-------------*/
      Rd_Hdr[i].data_start = ((U_INT32)&Rd_Buf[i][0]
                                       - (U_INT32)DMA_MEM);
/*-----------------end change---------------*/
      Rd_Hdr[i].data_length = 0x14;
      Rd_Hdr[i].max_data_len = RD_BUF_SIZE;
      /* put all packets on the queue of free packets */
      AppendPacket(&Rd_Hdr[i], Rd_Free_Q);
    }
    pthread_mutex_unlock(&Rd_Free_Q_Mut);

   /******  WRITE PACKETS  ******/

   /* initialize write queues */
   Wr_Free_Q.head = NULL;
   Wr_Free_Q.tail = NULL;
   Wr_Free_Q.num_entries = 0;

   for( i = 0; i < NUM_PORTS ; i++ )
   {
      Wr_Output_Q[i].head = NULL;
      Wr_Output_Q[i].tail = NULL;
      Wr_Output_Q[i].num_entries = 0;
   }

   /* initialize write packet headers */
   for (i = 0; i < NUM_WR_PACKETS ; i++)
   {
      Wr_Hdr[i].buf_type = DATA_WR;
      /* find 16 bit offset (required for MIO header) */
/*------------changed by wangwei----------------*/
      Wr_Hdr[i].data_start = ((U_INT32)&Wr_Buf[i][0]
                                 - (U_INT32)DMA_MEM);
/*--------------end change----------------------*/
      Wr_Hdr[i].data_length = 0x0;
      Wr_Hdr[i].max_data_len = WR_BUF_SIZE;
      /* put all packets on the queue of free packets */
      AppendPacket(&Wr_Hdr[i], Wr_Free_Q);
   }



   /***** Setup input message pointer and count which is used in Scan *******/
   Cmd_Proc_CB.pin_msg = NULL;
   Cmd_Proc_CB.in_msg_len = 0;
   Wkfile_CB.pin_msg = NULL;
   Wkfile_CB.in_msg_len = 0;

   /******  CMD BUFFERS  ******/
   /* initialize cmd queues */
   Free_Cmd_Q.head = NULL;
   Free_Cmd_Q.tail = NULL;
   Free_Cmd_Q.num_entries = 0;

   GC_Cmd_Q.head = NULL;
   GC_Cmd_Q.tail = NULL;
   GC_Cmd_Q.num_entries = 0;

   S1_Cmd_Q.head = NULL;
   S1_Cmd_Q.tail = NULL;
   S1_Cmd_Q.num_entries = 0;

   S2_Cmd_Q.head = NULL;
   S2_Cmd_Q.tail = NULL;
   S2_Cmd_Q.num_entries = 0;

   SP_Cmd_Q.head = NULL;
   SP_Cmd_Q.tail = NULL;
   SP_Cmd_Q.num_entries = 0;

   SS_Cmd_Q.head = NULL;
   SS_Cmd_Q.tail = NULL;
   SS_Cmd_Q.num_entries = 0;

   CC_Cmd_Q.head = NULL;
   CC_Cmd_Q.tail = NULL;
   CC_Cmd_Q.num_entries = 0;

   OV_Cmd_Q.head = NULL;
   OV_Cmd_Q.tail = NULL;
   OV_Cmd_Q.num_entries = 0;

   IX_Cmd_Q.head = NULL;
   IX_Cmd_Q.tail = NULL;
   IX_Cmd_Q.num_entries = 0;

   DX_Cmd_Q.head = NULL;
   DX_Cmd_Q.tail = NULL;
   DX_Cmd_Q.num_entries = 0;

   CX_Cmd_Q.head = NULL;
   CX_Cmd_Q.tail = NULL;
   CX_Cmd_Q.num_entries = 0;

   AX_Cmd_Q.head = NULL;
   AX_Cmd_Q.tail = NULL;
   AX_Cmd_Q.num_entries = 0;

   VX_Cmd_Q.head = NULL;
   VX_Cmd_Q.tail = NULL;
   VX_Cmd_Q.num_entries = 0;

   IQ_Cmd_Q.head = NULL;
   IQ_Cmd_Q.tail = NULL;
   IQ_Cmd_Q.num_entries = 0;

   AS_Cmd_Q.head = NULL;
   AS_Cmd_Q.tail = NULL;
   AS_Cmd_Q.num_entries = 0;

   _0X_Cmd_Q.head = NULL;
   _0X_Cmd_Q.tail = NULL;
   _0X_Cmd_Q.num_entries = 0;

   PX_Cmd_Q.head = NULL;
   PX_Cmd_Q.tail = NULL;
   PX_Cmd_Q.num_entries = 0;

   Q0_Cmd_Q.head = NULL;
   Q0_Cmd_Q.tail = NULL;
   Q0_Cmd_Q.num_entries = 0;

   Q1_Cmd_Q.head = NULL;
   Q1_Cmd_Q.tail = NULL;
   Q1_Cmd_Q.num_entries = 0;

   Q2_Cmd_Q.head = NULL;
   Q2_Cmd_Q.tail = NULL;
   Q2_Cmd_Q.num_entries = 0;

   Q3_Cmd_Q.head = NULL;
   Q3_Cmd_Q.tail = NULL;
   Q3_Cmd_Q.num_entries = 0;

   Ping_Q.head = NULL;
   Ping_Q.tail = NULL;
   Ping_Q.num_entries = 0;

   Inj_Q.head = NULL;
   Inj_Q.tail = NULL;
   Inj_Q.num_entries = 0;

   DT_Cmd_Q.head = NULL;
   DT_Cmd_Q.tail = NULL;
   DT_Cmd_Q.num_entries = 0;

   TP_Cmd_Q.head = NULL;
   TP_Cmd_Q.tail = NULL;
   TP_Cmd_Q.num_entries = 0;

   /* put all cmd buffers on free command queue */
   for (i = 0; i < NUM_CMD_BUFS ; i++)
   {
      AppendCmd(&Cmd_In[i], Free_Cmd_Q);
   }


/* initialize download and upload variables */

   Install_State = INSTALL_IDLE;

   for (i = 0; i <= 3; i++)
   {
      Dwnld_wkfile[i].p_buffer = Dwnld_wkfile[i].buffer; /* ptr to incoming msg */
      Dwnld_wkfile[i].length = 0;                     /* length of command */
      Dwnld_wkfile[i].install_request = FALSE;        /* ptr to incoming msg */
      Dwnld_wkfile[i].install_done = FALSE;           /* length of command */
      Dwnld_wkfile[i].p_install_begin = Dwnld_wkfile[i].buffer; /* ptr to incoming msg */
      Dwnld_wkfile[i].install_len = 0;                /* length of command */

      Upld_wkfile[i].p_buffer = Upld_wkfile[i].buffer;   /* ptr to Upload workfile */
      Upld_wkfile[i].length = 0;                      /* length of workfile */
      Upld_wkfile[i].max_len = 0;                     /* maximum length of workfile */
      Upld_wkfile[i].create_request = FALSE;
      Upld_wkfile[i].create_done = FALSE;
      Upld_wkfile[i].hex_crc[0] = 'N';
      Upld_wkfile[i].hex_crc[1] = 'O';
      Upld_wkfile[i].hex_crc[2] = 'N';
      Upld_wkfile[i].hex_crc[3] = 'E';
   }



   /* initialize pass thru communication paths */

   for( i = 0 ; i < NUM_PATHS ; i++ )
   {
      Com_Path[i].idsap.int_idsap  = MAKEINT('P',('A'+i));
      Com_Path[i].hdsap.int_hdsap = 0;
      Com_Path[i].host_port = 0;
   }

#  ifdef  BC_DEBUG
      /* initialize debug buffers */
      pTMP_CP = (U_INT8  *)TMP_CP;
      pTMP_CP_End = (U_INT8  *)&TMP_CP[2047];
      for ( i=0;i<200;i++)
      {
         *(pTMP_CP+i) = 0;
      }
#  endif


}

#ifndef mccabe
#  pragma SECTION UNDO
#endif

/***********************************************************************/
/* END FUNCTION: InitializeCmpProc                                     */
/***********************************************************************/




/***********************************************************************/
/* FUNCTION: CleanUpMsg                                                */
/* ========                                                            */
/*                                                                     */
/* PURPOSE: cleans up message for next scan.                           */
/*            if len = 0: do nothing                                   */
/*            if error: move pointer to next command or end of message */
/*            if ';': move pointer to next command or end of message   */
/*                                                                     */
/*                                                                     */
/* FILE SCOPE STATICS USED:                                            */
/*                                                                     */
/*                                                                     */
/* CALLS:                                                              */
/*                                                                     */
/* LIMITATIONS:                                                        */
/*                                                                     */
/* WARNINGS:                                                           */
/*                                                                     */
/*                                                                     */
/***********************************************************************/


void CleanUpMsg(IN_MSG_CB_TYPE  *msg)
{
   /* if length = 0, there is nothing to do */
   while( ((*msg).in_msg_len != 0) && (*(*msg).pin_msg != ';') )
   {
      /* move to next character */
      (*msg).pin_msg++;
      (*msg).in_msg_len--;
   }
   if( (*(*msg).pin_msg == ';') && ((*msg).in_msg_len != 0) )
   {
      (*msg).pin_msg++;
      (*msg).in_msg_len--;
   }
}
/***********************************************************************/
/* END FUNCTION: CleanUpMsg                                            */
/***********************************************************************/




/***********************************************************************/
/* FUNCTION: ExecuteWkFile                                             */
/* ========                                                            */
/*                                                                     */
/* PURPOSE: process commands loaded into the workfile build area.      */
/*      This function should not be called directly.  Use              */
/*      InstallWkFile.                                                 */
/*                                                                     */
/*     No need to use IQ_Cmd_Q for workfile since commands are         */
/*         executed in order.                                          */
/*                                                                     */
/* LIMITATIONS:                                                        */
/*                                                                     */
/* WARNINGS:                                                           */
/*                                                                     */
/***********************************************************************/

void ExecuteWkFile(BIT8  *p_begin, U_INT16 length)
{

/*------------changed by wangwei--------------------*/
  printf("call ExecuteWkFile\n");
/*--------------end change--------------------------*/

   /* signal workfile execution complete */
}
/***********************************************************************/
/* END FUNCTION: ExecuteWkFile                                         */
/***********************************************************************/



/***********************************************************************/
/* FUNCTION: Append2WkFile                                             */
/* ========                                                            */
/*                                                                     */
/* PURPOSE: Append commands from this download command to the          */
/*        workfile build area.                                         */
/*                                                                     */
/* GLOBALS USED:                                                       */
/*       Dwnld_wkfile.length                                           */
/*       Dwnld_wkfile.buffer                                           */
/*       Dwnld_wkfile.p_buffer                                         */
/*                                                                     */
/* FILE SCOPE STATICS USED:                                            */
/*                                                                     */
/*                                                                     */
/* CALLS:                                                              */
/*                                                                     */
/* LIMITATIONS:                                                        */
/*                                                                     */
/* WARNINGS:                                                           */
/*                                                                     */
/***********************************************************************/
U_INT16 Append2WkFile(IN_MSG_CB_TYPE  *msg, U_INT16 chan)
{
/*------------changed by wangwei--------------------*/
  printf("call Append2WkFile\n");
  return 0;
/*--------------end change--------------------------*/

}
/***********************************************************************/
/* END FUNCTION: Append2WkFile                                         */
/***********************************************************************/

/***********************************************************************/
/* FUNCTION: LoadHexCrc                                                */
/* ========                                                            */
/*                                                                     */
/* PURPOSE: Load the workfile's CRC into the Dwnld_wkfile.hex_crc.     */
/*                                                                     */
/* LIMITATIONS:                                                        */
/*                                                                     */
/* WARNINGS:                                                           */
/*                                                                     */
/***********************************************************************/
UI_ERR LoadHexCrc(IN_MSG_CB_TYPE *msg, U_INT16 chan)
{
U_INT16 count;
   /* locate first '"' */
   while( (*(*msg).pin_msg != '"') && ((*msg).in_msg_len != 0) )
   {
      (*msg).pin_msg++;
      (*msg).in_msg_len--;
   }
   if((*msg).in_msg_len != 0)
   {
      /* remove '"' */
      (*msg).pin_msg++;
      (*msg).in_msg_len--;
   }

   /* locate ending '"' */
   while( (*((*msg).pin_msg+(*msg).in_msg_len-1) != '"') && ((*msg).in_msg_len != 0) )
   {
      (*msg).in_msg_len--;
   }
   if((*msg).in_msg_len != 0)
   {
      /* remove '"' */
      (*msg).in_msg_len--;
   }

   /* copy everything between quotes to Dwnld buffer */
   if((*msg).in_msg_len == 4)
   {
      if(StrNCmp((*msg).pin_msg,(BIT8  *)"NONE",4))
      {
         StrNCpy(Dwnld_wkfile[chan].hex_crc,(BIT8 *)"NONE",4);
         return OK;
      }
      else
      {
         for( count = 0; count < 4; count++)
         {
            Dwnld_wkfile[chan].hex_crc[count] = *(*msg).pin_msg++;
            (*msg).in_msg_len--;
         }
         return OK;
      }
   }
   else
   {
      StrNCpy(Dwnld_wkfile[chan].hex_crc,(BIT8 *)"NONE",4);
      return INVALID_PARAM;
   }

}
/***********************************************************************/
/* END FUNCTION: LoadHexCrc                                            */
/***********************************************************************/



/***********************************************************************/
/* FUNCTION: CmdsInQueue                                               */
/* ========                                                            */
/*                                                                     */
/* PURPOSE: This function returns the number of commands in all of     */
/*        the command queues.                                          */
/*                                                                     */
/* LIMITATIONS:                                                        */
/*                                                                     */
/* WARNINGS:                                                           */
/*                                                                     */
/***********************************************************************/

U_INT16 CmdsInQueue(void)
{
   return GC_Cmd_Q.num_entries +
          S1_Cmd_Q.num_entries +
          S2_Cmd_Q.num_entries +
          SP_Cmd_Q.num_entries +
          SS_Cmd_Q.num_entries +
          CC_Cmd_Q.num_entries +
          OV_Cmd_Q.num_entries +
          IX_Cmd_Q.num_entries +
          DX_Cmd_Q.num_entries +
          CX_Cmd_Q.num_entries +
          AX_Cmd_Q.num_entries +
          VX_Cmd_Q.num_entries +
          AS_Cmd_Q.num_entries +
          DT_Cmd_Q.num_entries +
          _0X_Cmd_Q.num_entries +
          PX_Cmd_Q.num_entries;
}
/***********************************************************************/
/* END FUNCTION: CmdsInQueue                                           */
/***********************************************************************/



/***********************************************************************/
/* FUNCTION: CmdProc                                                   */
/* ========                                                            */
/*                                                                     */
/* PURPOSE: This function will parse up to one command from the input. */
/*        If more than one command arrives in the input, only one will */
/*        be parsed for each execution.  The other commands will be    */
/*        kept in the input queue until all are parsed.                */
/*                                                                     */
/*        Because of dependences between the oven, detector, inlets    */
/*        and columns, these commands are combined into one one queue  */
/*        called IQ_Cmd_Q.   This will allow the commands to be        */
/*        in the order they arrived.                                   */
/*                                                                     */
/* LIMITATIONS:                                                        */
/*                                                                     */
/* WARNINGS:                                                           */
/*                                                                     */
/***********************************************************************/

void CmdProc(void)
{
UI_ERR     error;
CMD_TYPE  *p_cmd;
U_INT16    delay;

   /* check if input message */
   /*
   if( ((Rd_Input_Q.num_entries != 0) ||
               (Cmd_Proc_CB.in_msg_len != 0)) )
   */
   if( ((Rd_Input_Q.num_entries != 0) || (Cmd_Proc_CB.in_msg_len != 0)) )

   {
    mLog("------CmdProc begin---------------\n");
      /* is there is a cmd buf available for Scan */
      INTERRUPTS_OFF;
      if(Free_Cmd_Q.num_entries <= 2)  /* save two cmd bufs for workfile */
      {
         /* no Free_Cmd available, do nothing this time */
         INTERRUPTS_ON;
      }
#if 0
      else if (Install_State != INSTALL_IDLE)
      {
         /* there is a method install in progress, let it complete */
         INTERRUPTS_ON;
      }
#endif
      else  /* Free_Cmd available */
      {
         GetCmdSafe(p_cmd, Free_Cmd_Q);
         INTERRUPTS_ON;

         /*if in_msg_len = 0, get new packet else continue parsing old packet*/
         if ( Cmd_Proc_CB.in_msg_len == 0 )
         {
            pthread_mutex_lock(&Rd_Input_Q_Mut);
            if(Rd_Input_Q.num_entries != 0)
            {
              GetPacket(pIn_Packet, Rd_Input_Q);
           
              /* set up command buffer header to indicate source of command */
              p_cmd->comm_port = pIn_Packet->comm_port;
           
              Cmd_Proc_CB.pin_msg = (BIT8 *)DMA_MEM + pIn_Packet->data_start; /* ptr msg */
              Cmd_Proc_CB.in_msg_len = pIn_Packet->data_length;  /* length of command */
           
              mLog("send packet to Cmd_Proc_CB from Rd_Input_Q\n");
            }
            else
            {
            }
            pthread_mutex_unlock(&Rd_Input_Q_Mut);
         }
         else
         {

            /* set up command buffer header to indicate source of command */
            p_cmd->comm_port = pIn_Packet->comm_port;

         }
         switch ( pIn_Packet->return_stat)
         {
            case  RET_OK:
            case  RET_NEW_CONN:
            case  RET_NORMAL_BREAK:
            case  RET_LOGICAL_BREAK:
               error = OK;
               error =  Scan(&Cmd_Proc_CB,p_cmd);
               mLog("scan cmd from Cmd_Proc_CB,error=%d\n",error);
               break;
            case  RET_PARTIAL_MSG:
               error = OK;
               error =  Scan(&Cmd_Proc_CB,p_cmd);
               break;
            case  RET_ABNORMAL_BREAK:
               error = LINK_ABNORMAL_BREAK;
               SetUpErrorMsgInCmd(&Cmd_Proc_CB,p_cmd);
               break;
            case  RET_DATA_OVERRUN:
               error = LINK_OVERRUN;
               SetUpErrorMsgInCmd(&Cmd_Proc_CB,p_cmd);
               break;
            case  RET_DATA_ERR:
               error = LINK_DATA_ERROR;
               SetUpErrorMsgInCmd(&Cmd_Proc_CB,p_cmd);
               break;
            default:
               error = LINK_ERROR;
               SetUpErrorMsgInCmd(&Cmd_Proc_CB,p_cmd);
               break;
         }


         CleanUpMsg(&Cmd_Proc_CB);
         if( !error )
         {

           pthread_mutex_lock(&Cmd_Q_Mut);
            switch (p_cmd->dsap.int_dsap)
            {
               case  MAKEINT('G','C'):
                  AppendCmd(p_cmd, IQ_Cmd_Q);
                  break;
               case  MAKEINT('S','1'):
                  AppendCmd(p_cmd, S1_Cmd_Q);
                  break;
               case MAKEINT('S','2'):
                  AppendCmd(p_cmd, S2_Cmd_Q);
                  break;
               case MAKEINT('S','P'):
                  AppendCmd(p_cmd, SP_Cmd_Q);
                  break;
               case MAKEINT('S','S'):
                  AppendCmd(p_cmd, SS_Cmd_Q);
                  break;
               case MAKEINT('C','C'):
                  /* calculate the channel number in case this is */
                  /* an upload or download command */
                  Cmd_Proc_CB.chan = p_cmd->comm_port;
                  /* to save storage space, use contiguous values */
                  /* by mapping ports 4 and 5 into 2 and 3 (sampler) */
                  if ( (Cmd_Proc_CB.chan == 4) || (Cmd_Proc_CB.chan == 5) )
                  {
                     Cmd_Proc_CB.chan -= 2;
                  }

                  /* check if this is a workfile command */
                  if( (p_cmd->opcode.int_op == MAKEINT('M','D')) ||
                      (p_cmd->opcode.int_op == MAKEINT('A','D')) ||
                      (p_cmd->opcode.int_op == MAKEINT('B','D'))   )
                  {
                     switch (p_cmd->parms[0])
                     {
                     case 'B':

                        /* copy to beginning of WkFile */
                        Dwnld_wkfile[Cmd_Proc_CB.chan].p_buffer =
                              Dwnld_wkfile[Cmd_Proc_CB.chan].buffer;

                        Dwnld_wkfile[Cmd_Proc_CB.chan].length = Append2WkFile(&Cmd_Proc_CB, Cmd_Proc_CB.chan);

                        AppendCmd(p_cmd, CC_Cmd_Q);
                        break;
                     case 'C':
                        /* append to WkFile */
                        Dwnld_wkfile[Cmd_Proc_CB.chan].length += Append2WkFile(&Cmd_Proc_CB, Cmd_Proc_CB.chan);

                        AppendCmd(p_cmd, CC_Cmd_Q);
                        break;
                     case 'E':
                        /* save length of command */
                        /* find CRC of WkFile */
                        if(LoadHexCrc(&Cmd_Proc_CB, Cmd_Proc_CB.chan) != OK)
                        {
                           /* error - invalid crc */
                           error = INVALID_PARAM;
                           CmdErrorHandler(p_cmd, 2, error);
                        }

                        AppendCmd(p_cmd, CC_Cmd_Q);
                        break;
                     case '?':
                     case '+':
                        /* used for workfile upload */
                        AppendCmd(p_cmd, CC_Cmd_Q);
                        break;
                     default:
                        /* error - no a valid parameter */
                        error = INVALID_PARAM;
                        CmdErrorHandler(p_cmd, 1, error);
                        AppendCmd(p_cmd, CC_Cmd_Q);
                        break;
                     }

                  }
                  else if( (p_cmd->opcode.int_op == MAKEINT('M','I')) ||
                           (p_cmd->opcode.int_op == MAKEINT('A','I')) ||
                           (p_cmd->opcode.int_op == MAKEINT('B','I')) ||
                           (p_cmd->opcode.int_op == MAKEINT('I','M'))   )
                  /* some form of install command */
                  /* make sure that no other commands are processed */
                  /* at the same time */
                  {
                     /* wait for all queued commands to complete */
                     /* timeout prevents possible lockups */
                     delay = 0;
                     while ( (CmdsInQueue() > 0) &&
                             (delay < 50) )
                     {
                        Task_yield();
                        delay++;
                     }
                     /* begin the install and wait for it to complete */
                     /* timeout prevents possible lockups */
                     Install_State = INSTALL_IDLE;
                     AppendCmd(p_cmd, CC_Cmd_Q);
#if 0
                     delay = 0;
                     while ( (Install_State != INSTALL_COMPLETE) &&
                             (delay < 150) )
                     {
                        Task_yield();
                        delay++;
                     }
#endif
                  }
                  else
                  {
                  AppendCmd(p_cmd, CC_Cmd_Q);
                  }

                  break;
               case MAKEINT('O','V'):
                  AppendCmd(p_cmd, IQ_Cmd_Q);
                  break;
               case MAKEINT('I','F'):
               case MAKEINT('I','B'):
                  AppendCmd(p_cmd, IQ_Cmd_Q);
                  break;
               case MAKEINT('D','F'):
               case MAKEINT('D','B'):
                  AppendCmd(p_cmd, IQ_Cmd_Q);
                  break;
               case MAKEINT('C','1'):
               case MAKEINT('C','2'):
                  AppendCmd(p_cmd, IQ_Cmd_Q);
                  break;
               case MAKEINT('A','1'):
               case MAKEINT('A','2'):
               case MAKEINT('A','3'):
               case MAKEINT('A','4'):
               case MAKEINT('A','5'):

                  mLog("Append Ax_Cmd to IQ_Cmd_Q\n");
                  AppendCmd(p_cmd, IQ_Cmd_Q);
                  break;
               case MAKEINT('V','1'):
               case MAKEINT('V','2'):
               case MAKEINT('V','3'):
               case MAKEINT('V','4'):
               case MAKEINT('V','5'):
               case MAKEINT('V','6'):
               case MAKEINT('V','7'):
               case MAKEINT('V','8'):
               case MAKEINT('V','X'):
                  AppendCmd(p_cmd, IQ_Cmd_Q);
                  break;
               case MAKEINT('I','Q'):
                  AppendCmd(p_cmd, IQ_Cmd_Q);
                  break;
               case MAKEINT('A','S'):
                  AppendCmd(p_cmd, AS_Cmd_Q);
                  break;
               case MAKEINT('Q','0'):
                  AppendCmd(p_cmd, Q0_Cmd_Q);
                  break;
               case MAKEINT('Q','1'):
                  AppendCmd(p_cmd, Q1_Cmd_Q);
                  break;
               case MAKEINT('Q','2'):
                  AppendCmd(p_cmd, Q2_Cmd_Q);
                  break;
               case MAKEINT('Q','3'):
                  AppendCmd(p_cmd, Q3_Cmd_Q);
                  break;
               case MAKEINT('\'','\''):
                  AppendCmd(p_cmd, Ping_Q);
                  break;
               case MAKEINT('i','n'):
                  AppendCmd(p_cmd, Inj_Q);
                  break;
               case MAKEINT('H','S'):
                  AppendCmd(p_cmd, HS_Cmd_Q);
                  break;
               case MAKEINT('D','T'):
                  AppendCmd(p_cmd, DT_Cmd_Q);
                  break;
               case MAKEINT('T','P'):
                  AppendCmd(p_cmd, TP_Cmd_Q);
                  break;
               default:

                  mLog("the Cmd is unkown,p_cmd->dsap.int_dsap:%d\n",p_cmd->dsap.int_dsap);
                  if(p_cmd->dsap.char_dsap[0] == '0')
                  {
                     AppendCmd(p_cmd, _0X_Cmd_Q);
                     break;
                  }
                  /* if pass thru cmd check range and if path is set up */
                  else if( (p_cmd->dsap.char_dsap[0] == 'P') &&
                         (p_cmd->dsap.char_dsap[1] >= 'A') &&
                         (p_cmd->dsap.char_dsap[1] < ('A'+NUM_PATHS)) )
                  {

                     /* check if path is set up */
                     if( Com_Path[p_cmd->dsap.char_dsap[1] - 'A'].
                           hdsap.int_hdsap != 0 )
                     {
                        AppendCmd(p_cmd, PX_Cmd_Q);
                        break;
                     }
                     else
                     {
                        /* ERROR: PATH NOT SET UP OR IN USE BY OTHER PORT */
                        /* ignore command */
                        error = INVALID_PATH;
                        CmdErrorHandler(p_cmd, 0, error);
                        AppendCmd(p_cmd, Free_Cmd_Q);
                        break;
                     }
                  }
                  else
                  {
                     /* ERROR: DESTINATION NOT VALID */
                     /* ignore command */
                     error = INVALID_DEST;
                     CmdErrorHandler(p_cmd, 0, error);
                     AppendCmd(p_cmd, Free_Cmd_Q);
                     break;
                  }
            }   /* switch */

            pthread_mutex_unlock(&Cmd_Q_Mut);
         }    /* if(!error) */
         else
         {
            /* ERROR: BAD INSTRUCTION */

            mLog("error: no such Cmd\n");
            CmdErrorHandler(p_cmd, 0, error);
            AppendCmd(p_cmd, Free_Cmd_Q);
         }


         if( Cmd_Proc_CB.in_msg_len == 0 )
         {
            /* done with In_Packet so return to Rd_Free_Q */

            {
            INTERRUPTS_OFF;
            /* transfer packet to driver */
            pthread_mutex_lock(&Rd_Free_Q_Mut);
            AppendPacket(pIn_Packet, Rd_Free_Q); /* CRITICAL REGION */
            pthread_mutex_unlock(&Rd_Free_Q_Mut);
               /* if waiting for rd packet, set up this one */
/* *WARNING*  *WARNING*  *WARNING*  *WARNING*  *WARNING*  *WARNING*  *WARNING* */
/* The following block LOOKS as if it does nothing, but in fact the function   */
/*  DuartWaitingRdPacket has side effects that are required! DO NOT delete the */
/*  following block of code.                                                   */
/*----------changed by wangwei------------*/
/*
               if(DuartWaitingRdPacket(DRTA_PORT) == TRUE)
               {
                  ;
               }
               else if(DuartWaitingRdPacket(DRTB_PORT)== TRUE)
               {
                  ;
               }
               else if(DuartWaitingRdPacket(DRTC_PORT)== TRUE)
               {
                  ;
               }
               else if(DuartWaitingRdPacket(DRTD_PORT)== TRUE)
               {
                  ;
               }
               else if(DuartWaitingRdPacket(DRTE_PORT)== TRUE)
               {
                  ;
               }
               else
               {
                  ;
               }
*/
/*---------------end change-------------------*/
/* End Warning */

            INTERRUPTS_ON;
            }

         }
      }  /* else  Free_Cmd available */

    mLog("------CmdProc end---------------\n");
   } /* if */


}

/***********************************************************************/
/* END FUNCTION: CmdProc                                               */
/***********************************************************************/
